﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;

namespace System.Web.Mvc.Html
{
    public class LigerUIGrid
    {
        public static MvcHtmlString CreateGrid<T>(LigerUIGridData<T> data)
        {
            return new MvcHtmlString(createGrid<T>(data));
        }

        public static MvcHtmlString CreateGrid<T, T1>(LigerUIDetailGridData<T, T1> data)
        {
            return new MvcHtmlString(createDetailGrid<T,T1>(data));
        }

        private static string createGrid<T>(LigerUIGridData<T> data)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script type='text/javascript'>");
            sb.AppendLine(string.Format("var {0};", data.GridName));
            
            sb.AppendLine(string.Format("var {1}={{Total:{0},", data.ItemList.Count, data.DataName));
            sb.AppendLine("Rows:[");
            for (int i = 0; i < data.ItemList.Count; i++)
            {
                var item = data.ItemList[i];
                if (i == 0)
                {
                    sb.Append("{");
                }
                else
                {
                    sb.Append(",{");
                }
                for (int j = 0; j < data.ColumnList.Count - 1; j++)
                {
                    var column = data.ColumnList[j];
                    sb.Append(string.Format("{0}:'{1}',", column.Field, column.GetValue(item)));
                }

                sb.Append(string.Format("{0}:'{1}'", data.ColumnList[data.ColumnList.Count - 1].Field, data.ColumnList[data.ColumnList.Count - 1].GetValue(item)));

                sb.Append("}");
            }
            sb.AppendLine("]};");
            sb.AppendLine("$(function (){");
            if (data.MenuList != null && data.MenuList.Count > 0)
            {
                sb.AppendLine(string.Format("var {0} = $.ligerMenu({{ top: 100, left: 100, width: 120, items:[", data.MenuName));
                for (int j = 0; j < data.MenuList.Count - 1; j++)
                {
                    sb.AppendLine(string.Format("{{ text: '{0}', click: {1} }},", data.MenuList[j].Text, data.MenuList[j].Function));
                    sb.AppendLine("{ line: true },");
                }
                if(data.MenuList.Count > 0)
                    sb.AppendLine(string.Format("{{ text: '{0}', click: {1} }}", data.MenuList[data.MenuList.Count - 1].Text, data.MenuList[data.MenuList.Count - 1].Function));
                sb.AppendLine("]});");
            }

            sb.AppendLine(string.Format("{1} = $('#{0}').ligerGrid({{", data.GridID, data.GridName));
            sb.AppendLine("columns: [");

            var temp = (from t in data.ColumnList
                        where t.IsShow
                        select t).ToList();
            for (int j = 0; j < temp.Count - 1; j++)
            {
                var column = temp[j];
                if (column.GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }},", column.Display, column.Field, column.Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', width:{2}, render: function (row){{ return {1}; }} }},", column.Display, column.GetRender(), column.Width));
            }
            if (temp.Count > 0)
            {
                if (temp[temp.Count - 1].GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }}", temp[temp.Count - 1].Display, temp[temp.Count - 1].Field, temp[temp.Count - 1].Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', render: function (row){{ return {1}; }} }}", temp[temp.Count - 1].Display, temp[temp.Count - 1].GetRender()));
            }
            sb.AppendLine("],");

            if (data.MenuList != null && data.MenuList.Count > 0)
                sb.AppendLine("onContextmenu: function (node, e) {actionNodeID = node;menu.show({ top: e.pageY, left: e.pageX });return false;},");
            if (!string.IsNullOrEmpty(data.Url))
            {
                sb.AppendLine(string.Format("url:'{0}',dataAction:'server',", data.Url));
            }
            sb.AppendLine(string.Format("isScroll: false, data: {0},pageSize:{1},alternatingRow:true}} );", data.DataName, data.PageSize));
            sb.AppendLine(string.Format("resetGridHeight({0});", data.GridName));
            sb.AppendLine(string.Format("$(window).resize(function () {{resetGridHeight({0});}});", data.GridName));
            
            sb.AppendLine("});");

            sb.AppendLine("</script>");

            return sb.ToString();
        }

        private static string createDetailGrid<T, T1>(LigerUIDetailGridData<T, T1> data)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script type='text/javascript'>");
            sb.AppendLine(string.Format("var {0};", data.GridName));
            sb.AppendLine(string.Format("var {1}={{Total:{0},", data.ItemList.Count, data.DataName));
            sb.AppendLine("Rows:[");
            for (int i = 0; i < data.ItemList.Count; i++)
            {
                var item = data.ItemList[i];
                if (i == 0)
                {
                    sb.Append("{");
                }
                else
                {
                    sb.Append(",{");
                }
                for (int j = 0; j < data.ColumnList.Count - 1; j++)
                {
                    var column = data.ColumnList[j];
                    sb.Append(string.Format("{0}:'{1}',", column.Field, column.GetValue(item)));
                }

                sb.Append(string.Format("{0}:'{1}'", data.ColumnList[data.ColumnList.Count - 1].Field, data.ColumnList[data.ColumnList.Count - 1].GetValue(item)));

                sb.Append("}");
            }
            sb.AppendLine("]};");

            sb.AppendLine(string.Format("var {1}={{Total:{0},", data.DetailItemList.Count, data.DetailDataName));
            sb.AppendLine("Rows:[");
            for (int i = 0; i < data.DetailItemList.Count; i++)
            {
                var item = data.DetailItemList[i];
                if (i == 0)
                {
                    sb.Append("{");
                }
                else
                {
                    sb.Append(",{");
                }
                for (int j = 0; j < data.DetailColumnList.Count - 1; j++)
                {
                    var column = data.DetailColumnList[j];
                    sb.Append(string.Format("{0}:'{1}',", column.Field, column.GetValue(item)));
                }

                sb.Append(string.Format("{0}:'{1}'", data.DetailColumnList[data.DetailColumnList.Count - 1].Field, data.DetailColumnList[data.DetailColumnList.Count - 1].GetValue(item)));

                sb.Append("}");
            }
            sb.AppendLine("]};");

            sb.AppendLine("$(function (){");
            if (data.MenuList != null && data.MenuList.Count > 0)
            {
                sb.AppendLine(string.Format("var {0} = $.ligerMenu({{ top: 100, left: 100, width: 120, items:[", data.MenuName));
                for (int j = 0; j < data.MenuList.Count - 1; j++)
                {
                    sb.AppendLine(string.Format("{{ text: '{0}', click: {1} }},", data.MenuList[j].Text, data.MenuList[j].Function));
                    sb.AppendLine("{ line: true },");
                }
                if (data.MenuList.Count > 0)
                    sb.AppendLine(string.Format("{{ text: '{0}', click: {1} }}", data.MenuList[data.MenuList.Count - 1].Text, data.MenuList[data.MenuList.Count - 1].Function));
                sb.AppendLine("]});");
            }

            sb.AppendLine(string.Format("{1} = $('#{0}').ligerGrid({{", data.GridID, data.GridName));
            sb.AppendLine("columns: [");

            var temp = (from t in data.ColumnList
                        where t.IsShow
                        select t).ToList();
            for (int j = 0; j < temp.Count - 1; j++)
            {
                var column = temp[j];
                if (column.GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }},", column.Display, column.Field, column.Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', width:{2}, render: function (row){{ return {1}; }} }},", column.Display, column.GetRender(), column.Width));
            }
            if (temp.Count > 0)
            {
                if (temp[temp.Count - 1].GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }}", temp[temp.Count - 1].Display, temp[temp.Count - 1].Field, temp[temp.Count - 1].Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', render: function (row){{ return {1}; }} }}", temp[temp.Count - 1].Display, temp[temp.Count - 1].GetRender()));
            }
            sb.AppendLine("],");

            if (data.MenuList != null && data.MenuList.Count > 0)
                sb.AppendLine("onContextmenu: function (node, e) {actionNodeID = node;menu.show({ top: e.pageY, left: e.pageX });return false;},");
            if (!string.IsNullOrEmpty(data.Url))
            {
                sb.AppendLine(string.Format("url:'{0}',dataAction:'server',", data.Url));
            }
            sb.AppendLine(string.Format("detail: {{ onShowDetail: {0},height:'auto'  }},", data.ShowDetailGridFunName));
            sb.AppendLine(string.Format("isScroll: false, frozen:false, data: {0},pageSize:{1},alternatingRow:true}} );", data.DataName, data.PageSize));
            sb.AppendLine(string.Format("resetGridHeight({0});", data.GridName));
            sb.AppendLine(string.Format("$(window).resize(function () {{resetGridHeight({0});}});", data.GridName));

            sb.AppendLine("});");

            sb.AppendLine(string.Format(" function {0}(row, detailPanel,callback){{",data.ShowDetailGridFunName));
            sb.AppendLine(string.Format("var {0} = document.createElement('div'); ", data.DetailGridName));
            sb.AppendLine(string.Format("$(detailPanel).append({0});", data.DetailGridName));
            sb.AppendLine(string.Format("$({0}).css('margin',10).ligerGrid({{", data.DetailGridName));
            sb.AppendLine("columns:[");
            var temp1 = (from t in data.DetailColumnList
                        where t.IsShow
                        select t).ToList();
            for (int j = 0; j < temp1.Count - 1; j++)
            {
                var column = temp1[j];
                if (column.GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }},", column.Display, column.Field, column.Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', width:{2}, render: function (row){{ return {1}; }} }},", column.Display, column.GetRender(), column.Width));
            }
            if (temp1.Count > 0)
            {
                if (temp1[temp1.Count - 1].GetRender() == "")
                    sb.Append(string.Format("{{ display: '{0}', name: '{1}',width:{2} }}", temp1[temp1.Count - 1].Display, temp1[temp1.Count - 1].Field, temp1[temp1.Count - 1].Width));
                else
                    sb.Append(string.Format("{{ display: '{0}', render: function (row){{ return {1}; }} }}", temp1[temp1.Count - 1].Display, temp1[temp1.Count - 1].GetRender()));
            }
            sb.AppendLine("],isScroll: false, showToggleColBtn: false, width: '90%',");
            sb.AppendLine(string.Format("data: {0}(row.{1}) , showTitle: false, columnWidth: 100, onAfterShowData: callback,frozen:false",data.GetDetailDataFunName,data.JoinColumnName));
            sb.AppendLine("});");
            sb.AppendLine("}");

            sb.AppendLine(string.Format("function {0}({1}){{", data.GetDetailDataFunName, data.JoinColumnName));
            sb.AppendLine("var temp = { Rows: [] };");
            sb.AppendLine(string.Format("for (var i = 0; i < {0}.Rows.length; i++){{",data.DetailDataName));
            sb.AppendLine(string.Format("if ({0}.Rows[i].{1} == {1})", data.DetailDataName, data.JoinColumnName));
            sb.AppendLine(string.Format("temp.Rows.push({0}.Rows[i]);", data.DetailDataName));
            sb.AppendLine("}");
            sb.AppendLine("return temp;");
            sb.AppendLine("}");

            sb.AppendLine("</script>");

            return sb.ToString();
        }
    }

    public class LigerUIDetailGridData<T, T1> : LigerUIGridData<T>
    {
        public LigerUIDetailGridData() 
        {
            DetailGridName = "detail_grid";
            DetailDataName = "detail_data";
            GetDetailDataFunName = "getDetailData";
            ShowDetailGridFunName = "showDetailGrid";
            DetailColumnList = new List<LigerUIGridItemData<T1>>();
        }

        public string DetailGridName { get; set; }
        public string DetailDataName { get; set; }
        public string GetDetailDataFunName { get; set; }
        public string ShowDetailGridFunName { get; set; }

        public List<LigerUIGridItemData<T1>> DetailColumnList { get; set; }
        public List<T1> DetailItemList { get; set; }

        public string JoinColumnName { get; set; }

        public LigerUIGridItemData<T1> CreateDetailRow(string field = "", string display = "", bool isShow = true, int width = 80)
        {
            var data = new LigerUIGridItemData<T1>()
            {
                Field = field,
                Display = display,
                IsShow = isShow,
                Width = width
            };
            this.DetailColumnList.Add(data);
            return data;
        }
    }

    public class LigerUIGridData<T>
    {
        public LigerUIGridData()
        {
            GridID = "maingrid";
            DataName = "data";
            GridName = "grid";
            MenuName = "menu";
            PageSize = 30;
            ColumnList = new List<LigerUIGridItemData<T>>();
        }

        public string Url { get; set; }
        public int? Page { get; set; }
        public string GridID { get; set; }
        public string DataName { get; set; }
        public string GridName { get; set; }
        public string MenuName { get; set; }
        public List<LigerUIGridItemData<T>> ColumnList { get; set; }
        public List<T> ItemList { get; set; }

        public List<LigerUIGridMenuData> MenuList { get; set; }

        public LigerUIGridItemData<T> CreateRow(string field = "",string display = "",bool isShow = true,int width = 80)
        {
            var data =  new LigerUIGridItemData<T>() 
            {
                Field = field,
                Display = display,
                IsShow = isShow,
                Width = width
            };
            this.ColumnList.Add(data);
            return data;
        }

        public int PageSize { get; set; }
        public int ItemCount { get; set; }
    }

    public class LigerUIGridItemData<T>
    {
        public LigerUIGridItemData()
        {
            IsShow = true;
        }

        public bool IsShow { get; set; }
        public string Field { get; set; }
        public string Display { get; set; }
        public int Width { get; set; }
        public delegate string StringDelegate();
        public delegate object ObjectDelegate(T item);

        public event ObjectDelegate ValueEvent;
        public object GetValue(T item)
        {
            if (ValueEvent == null)
                return "";
            else
                return ValueEvent(item);
        }
        public event StringDelegate RenderEvent;
        public string GetRender()
        {
            if (RenderEvent == null)
                return "";
            else
                return RenderEvent();
        }
    }

    public class LigerUIGridMenuData
    {
        public string Text { get; set; }
        public string Function { get; set; }
    }
}